namespace SimpleWebServices.Configuration
{
    using System.Configuration;
    using System.Xml;
    using System.Xml.XPath;
    using SimpleWebServices;
    using Xunit;

    public sealed class RedirectionConfigurationFacts
    {
        [Fact]
        public void typedef()
        {
            Assert.True(new ObjectExpectations<RedirectionConfiguration>()
                .DerivesFrom<object>()
                .IsConcreteClass()
                .IsSealed()
                .HasDefaultConstructor()
                .XmlRoot("redirection")
                .Implements<IConfigurationSectionHandler>()
                .Result);
        }

        [Fact]
        public void deserialize()
        {
            RedirectionConfiguration actual = (
                "<redirection>" +
                    "<domains>" +
                        "<redirect from='example.com' to='www.example.com' />" +
                    "</domains>" +
                    "<paths>" +
                        "<redirect from='/foo' to='/bar' />" +
                    "</paths>" +
                    "<uri>" +
                        "<redirect from='http://www.example.com/abc' to='http://www.example.net/xyz' />" +
                    "</uri>" +
                "</redirection>").Deserialize<RedirectionConfiguration>();

            Assert.Equal<string>("example.com", actual.Domains[0].From);
            Assert.Equal<string>("www.example.com", actual.Domains[0].To);

            Assert.Equal<string>("/foo", actual.Paths[0].From);
            Assert.Equal<string>("/bar", actual.Paths[0].To);

            Assert.Equal<string>("http://www.example.com/abc", actual.Uri[0].From);
            Assert.Equal<string>("http://www.example.net/xyz", actual.Uri[0].To);
        }

        [Fact]
        public void deserializeEmpty()
        {
            RedirectionConfiguration actual = "<redirection />".Deserialize<RedirectionConfiguration>();

            Assert.NotNull(actual);

            Assert.Empty(actual.Domains);
            Assert.Empty(actual.Paths);
            Assert.Empty(actual.Uri);
        }

        [Fact]
        public void serialize()
        {
            RedirectionConfiguration obj = new RedirectionConfiguration
            {
                Domains = new RedirectionCollection
                {
                    new RedirectionSetting
                    {
                        From = "example.com",
                        To = "www.example.com"
                    }
                },
                Paths = new RedirectionCollection
                {
                    new RedirectionSetting
                    {
                        From = "/foo",
                        To = "/bar"
                    }
                },
                Uri = new RedirectionCollection
                {
                    new RedirectionSetting
                    {
                        From = "http://www.example.com/abc",
                        To = "http://www.example.net/xyz"
                    }
                }
            };

            XPathNavigator navigator = obj.Serialize().CreateNavigator();

            Assert.True((bool)navigator.Evaluate("1=count(/redirection/domains/redirect[@from='example.com'][@to='www.example.com'])"));
            Assert.True((bool)navigator.Evaluate("1=count(/redirection/paths/redirect[@from='/foo'][@to='/bar'])"));
            Assert.True((bool)navigator.Evaluate("1=count(/redirection/uri/redirect[@from='http://www.example.com/abc'][@to='http://www.example.net/xyz'])"));
        }

        [Fact]
        public void ctor()
        {
            Assert.NotNull(new RedirectionConfiguration());
        }

        [Fact]
        public void prop_Domains()
        {
            Assert.True(new PropertyExpectations(typeof(RedirectionConfiguration).GetProperty("Domains"))
                .XmlElement("domains")
                .TypeIs<RedirectionCollection>()
                .DefaultValueIsNotNull()
                .Result);
        }

        [Fact]
        public void prop_Paths()
        {
            Assert.True(new PropertyExpectations(typeof(RedirectionConfiguration).GetProperty("Paths"))
                .XmlElement("paths")
                .TypeIs<RedirectionCollection>()
                .DefaultValueIsNotNull()
                .Result);
        }

        [Fact]
        public void prop_Uri()
        {
            Assert.True(new PropertyExpectations(typeof(RedirectionConfiguration).GetProperty("Uri"))
                .XmlElement("uri")
                .TypeIs<RedirectionCollection>()
                .DefaultValueIsNotNull()
                .Result);
        }

        [Fact]
        public void op_Settings()
        {
            Assert.NotNull(RedirectionConfiguration.Settings());
        }

        [Fact]
        public void op_Settings_string()
        {
            Assert.NotNull(RedirectionConfiguration.Settings("simplewebservices/redirection"));
        }

        [Fact]
        public void op_Create_object_object_XmlNodeNull()
        {
            RedirectionConfiguration actual = new RedirectionConfiguration().Create(null, null, null as XmlNode) as RedirectionConfiguration;

            Assert.NotNull(actual);
        }

        [Fact]
        public void op_Create_object_object_XmlNodeEmpty()
        {
            XmlDocument xml = new XmlDocument();
            xml.LoadXml("<redirection />");

            RedirectionConfiguration actual = new RedirectionConfiguration().Create(null, null, xml.DocumentElement) as RedirectionConfiguration;

            Assert.NotNull(actual);
        }

        [Fact]
        public void op_Create_object_object_XmlNode()
        {
            XmlDocument xml = new XmlDocument();
            xml.LoadXml(
                "<redirection>" +
                    "<domains>" +
                        "<redirect from='example.com' to='www.example.com' />" +
                    "</domains>" +
                    "<paths>" +
                        "<redirect from='/foo' to='/bar' />" +
                    "</paths>" +
                    "<uri>" +
                        "<redirect from='http://www.example.com/abc' to='http://www.example.net/xyz' />" +
                    "</uri>" +
                "</redirection>");

            RedirectionConfiguration actual = new RedirectionConfiguration().Create(null, null, xml.DocumentElement) as RedirectionConfiguration;

            Assert.Equal<int>(1, actual.Domains.Count);
            Assert.Equal<int>(1, actual.Paths.Count);
            Assert.Equal<int>(1, actual.Uri.Count);
        }

        [Fact]
        public void op_Create_object_object_XmlNodeInvalid()
        {
            XmlDocument xml = new XmlDocument();
            xml.LoadXml("<bad-name/>");

            Assert.Throws<ConfigurationErrorsException>(() => new RedirectionConfiguration().Create(null, null, xml.DocumentElement));
        }
    }
}